package edu.colorado.karl.devices;

import java.util.ArrayList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.colorado.karl.databases.ErrorDatabaseResult;
import edu.colorado.karl.databases.LongTermDatabase;
import edu.colorado.karl.databases.SPResponse;
import edu.colorado.karl.databases.SensorResponse;
import edu.colorado.karl.databases.SetpointsDatabase;

/**
 * Represents the Room State device.  This device is responsible for obtaining
 * and displaying the following information:
 * <ul>
 * <li>Indoor Temperature</li>
 * <li>Outside Air Temperature</li>
 * <li>Heating and Cooling Room Set Points</li>
 * <li>If the house is Heating or Cooling</li>
 * </ul>
 * @author Michael Knudson
 * @version 4/27/08
 */
public class RoomState {
	//	Used for log4j logging
	private static final Log log = LogFactory.getLog(RoomState.class);
	
	/**
	 * Sole constructor.
	 */
	public RoomState() {
		
	}
	
	/**
	 * Returns the last indoor and outdoor air temperatures recorded in the 
	 * Long-Term Database.  If an error occurs while retrieving a temperature,
	 * the Long_Term_Fail error is set and the value "0.0" is returned for
	 * that temperature.
	 * @return a two-element double array containing the air temperatures.
	 * Index 0 contains the room temperature while index 1 contains the outdoor
	 * temperature.
	 */
	public double[] getAirTemps() {
		LongTermDatabase ltdb = new LongTermDatabase();
		double[] temps = new double[2];
		temps[0] = -666;
		temps[1] = -666;
		
		ArrayList<SensorResponse> ltl = ltdb.getAirTemperatures();
		for (SensorResponse response : ltl) {
			if(response.getName().equals("RT"))
				temps[0] = response.getValue();
			if(response.getName().equals("OAT"))
				temps[1] = response.getValue();
		}
		
		if(temps[0] == -666) {
			log.error("Current State unable to find current Room Temperature.");
			temps[0] = 0.0;
			ErrorDatabaseResult.activateError(ErrorDatabaseResult.LONG_TERM_FAIL);
		}
		if(temps[1] == -666) {
			log.error("Current State unable to find current Outside Air Temperature.");
			temps[1] = 0.0;
			ErrorDatabaseResult.activateError(ErrorDatabaseResult.LONG_TERM_FAIL);
		}
		
		return temps;
	}
	
	/**
	 * Returns the room set points from the Setpoints Database.  If an error 
	 * occurs while retrieving a set point, the Setpoints_Fail error is set and
	 * the value "0" is used for that set point.
	 * <p>The values in the int array returned are as follows:
	 * <ul><li>[0] Room Set Point</li>
	 * <li>[1] Room Set Point Differential</li>
	 * <li>[2] House Heating Mode</li>
	 * </ul>
	 * <p>The House Heating Mode can be either -1 (indicating "cooling"), 1
	 * (indicating "heating"), or 0 (indicating "off").
	 * @return a three-element int array containing set point information.
	 */
	public int[] getSetPoints(double roomTemp) {
		SetpointsDatabase spdb = new SetpointsDatabase();
		int[] sps = new int[3];
		
		for (int i = 0; i < sps.length; i++) {
			sps[1] = -666;	// initialization flag
		}
		
		ArrayList<SPResponse> spl = spdb.getRoomSetPoints();
		
		for (SPResponse val : spl) {
			if(val.getName().equals(SetpointsDatabase.ROOM_TEMP))
				sps[0] = val.getValue();
			else if(val.getName().equals(SetpointsDatabase.ROOM_RANGE))
				sps[1] = val.getValue();
		}
		
		if(sps[0] == -666) {
			log.error("Current State unable to find Room Temperature Set Point.");
			sps[0] = 0;
			ErrorDatabaseResult.activateError(ErrorDatabaseResult.SETPOINTS_FAIL);
		}
		
		if(sps[1] == -666) {
			log.error("Current State unable to find Room Temperature Set Point Range.");
			sps[1] = 0;
			ErrorDatabaseResult.activateError(ErrorDatabaseResult.SETPOINTS_FAIL);
		}
		
		//	Determine Heating Mode
		int coolSP = sps[0] - sps[1];
		int heatSP = sps[0] + sps[1];
		
		if(roomTemp < coolSP)
			sps[2] = -1;	// Cooling
		else if(roomTemp > heatSP)
			sps[2] = +1;	// Heating
		else
			sps[2] = 0;		// Off
		
		return sps;
	}
}
